import {
  IDetectProfileOptions,
  INodePtyInstance,
  IShellLaunchConfig,
  ITerminalError,
  ITerminalNodeService,
  ITerminalProfile,
  ITerminalServiceClient,
} from '../common';
import {
  WINDOWS_DEFAULT_SHELL_PATH_MAPS,
  WindowsShellType,
} from '../common/shell';

import {
  WINDOWS_GIT_BASH_PATHS,
  findShellExecutableAsync,
  getSystemShell,
} from './shell';
import { isMacintosh, isWindows, OperatingSystem } from '../../utils';
import { TerminalProfileServiceNode } from './terminal.profile.service';
import { BrowserWindow } from 'electron';

/**
 * this RPC target: NodePtyTerminalService
 */
interface IRPCTerminalService {
  closeClient(
    id: string,
    data: ITerminalError | { code?: number; signal?: number } | number,
    signal?: number
  ): void;

  $processChange(id: string, processName: string): void;

  onMessage(id: string, msg: string): void;
}

export class RPCTerminalServiceImpl implements IRPCTerminalService {
  constructor(private win: BrowserWindow) {}

  closeClient(id, data) {
    this.win.webContents.send(
      'terminal:onSessionExit',
      id,
      JSON.stringify(data)
    );
  }

  onMessage(id, msg) {
    this.win.webContents.send('terminal:onSessionData', id, msg); // ✅ 发给前端
  }

  $processChange(id, processName) {
    this.win.webContents.send('terminal:onProcessChange', id, processName);
  }
}

export abstract class RPCService<T = any> {
  rpcClient?: T[];

  get client(): T | undefined {
    return this.rpcClient ? this.rpcClient[0] : undefined;
  }
}

/**
 * 标准的后端服务，供前端调用
 * 目前每个窗口会对应一个 TerminalServiceClientImpl 实例
 */
export class TerminalServiceClientImpl
  extends RPCService<IRPCTerminalService>
  implements ITerminalServiceClient
{
  private clientId: string;

  constructor(
    private terminalService: ITerminalNodeService,
    private terminalProfileService: TerminalProfileServiceNode
  ) {
    super();
  }

  /**
   * 设置连接的 clientId，并注册当前 client 到 terminalService
   * @param clientId 客户端唯一标识
   */
  setConnectionClientId(clientId: string) {
    this.clientId = clientId;
    this.terminalService.setClient(this.clientId, this);
  }

  /**
   * 向前端 client 发送消息
   * @param id 终端 id
   * @param data 消息内容
   */
  clientMessage(id: string, data: string) {
    if (this.client) {
      return this.client.onMessage(id, data);
    } else {
      console.warn(`clientMessage ${id} rpcClient not found`);
    }
  }

  /**
   * 通知前端关闭终端
   * @param id 终端 id
   * @param data 错误或退出信息
   * @param signal 退出信号
   */
  closeClient(
    id: string,
    data: ITerminalError | { code?: number; signal?: number } | number,
    signal?: number
  ) {
    if (this.client) {
      this.client.closeClient(id, data, signal);
    } else {
    }
  }

  /**
   * 通知前端进程名变更
   * @param clientId 客户端 id
   * @param processName 进程名
   */
  processChange(clientId: string, processName: string): void {
    if (this.client) {
      this.client.$processChange(clientId, processName);
    }
  }

  /**
   * 检查终端状态，终端是否存活
   * @param terminalIdArr 终端 id 数组
   */
  async ensureTerminal(terminalIdArr: string[]): Promise<boolean> {
    return await this.terminalService.ensureClientTerminal(
      this.clientId,
      terminalIdArr
    );
  }

  /**
   * 创建终端实例
   * @param id 终端 id
   * @param cols 列数
   * @param rows 行数
   * @param launchConfig 启动配置
   */
  async create2(
    id: string,
    cols: number,
    rows: number,
    launchConfig: IShellLaunchConfig
  ): Promise<INodePtyInstance | undefined> {
    try {
      const pty = await this.terminalService.create2(
        id,
        cols,
        rows,
        launchConfig
      );

      if (pty) {
        this.terminalService.setClient(this.clientId, this);

        return {
          id,
          pid: pty.pid,
          process: pty.process,
          name: pty.parsedName,
          shellPath: pty.launchConfig.executable,
        };
      } else {
        console.error('Failed to create terminal instance:', id);
        return undefined;
      }
    } catch (error) {
      console.error('Error creating terminal instance:', error);
      // 这里可以抛出错误或返回 undefined，根据具体需求决定
      return undefined;
    }
  }

  /**
   * 解析 Windows 下的 shell 路径
   * @param type shell 类型
   */
  async $resolveWindowsShellPath(
    type: WindowsShellType
  ): Promise<string | undefined> {
    switch (type) {
      case WindowsShellType.powershell:
        return WINDOWS_DEFAULT_SHELL_PATH_MAPS.powershell;
      case WindowsShellType.cmd:
        return WINDOWS_DEFAULT_SHELL_PATH_MAPS.cmd;
      case WindowsShellType['git-bash']: {
        const shell = await findShellExecutableAsync(WINDOWS_GIT_BASH_PATHS);
        return shell;
      }
      default:
        // 未知的 shell，返回 undefined，后续会使用系统默认值处理
        return undefined;
    }
  }

  /**
   * 解析 Unix 下的 shell 路径
   * @param type shell 类型
   */
  async $resolveUnixShellPath(type: string): Promise<string | undefined> {
    const candidates = [type, `/bin/${type}`, `/usr/bin/${type}`];
    return await findShellExecutableAsync(candidates);
  }

  /**
   * 解析 shell 路径，传入候选路径数组
   * @param paths 候选路径
   */
  async $resolveShellPath(paths: string[]): Promise<string | undefined> {
    return await findShellExecutableAsync(paths);
  }

  /**
   * 检测可用的终端 profiles
   * @param options 检测参数
   */
  async detectAvailableProfiles(
    options: IDetectProfileOptions
  ): Promise<ITerminalProfile[]> {
    return await this.terminalProfileService.detectAvailableProfiles(options);
  }

  /**
   * 获取 code 平台 key
   */
  async getCodePlatformKey(): Promise<'osx' | 'windows' | 'linux'> {
    switch (this.getOS()) {
      case OperatingSystem.Macintosh:
        return 'osx';
      case OperatingSystem.Windows:
        return 'windows';
      case OperatingSystem.Linux:
        return 'linux';
      default:
        return 'linux';
    }
  }

  /**
   * 获取系统默认 shell 路径
   * @param os 操作系统类型
   */
  async getDefaultSystemShell(os: OperatingSystem) {
    return await getSystemShell(os);
  }

  /**
   * 处理前端发来的消息
   * @param id 终端 id
   * @param msg 消息内容
   */
  onMessage(id: string, msg: string): void {
    const { data, params, method } = JSON.parse(msg);

    if (method === 'resize') {
      this.resize(id, params.rows, params.cols);
    } else {
      this.terminalService.onMessage(id, data);
    }
  }

  /**
   * 调整终端尺寸
   * @param id 终端 id
   * @param rows 行数
   * @param cols 列数
   */
  resize(id: string, rows: number, cols: number) {
    this.terminalService.resize(id, rows, cols);
  }

  /**
   * 销毁指定 id 的终端
   * @param id 终端 id
   */
  disposeById(id: string) {
    this.terminalService.disposeById(id);
  }

  /**
   * 获取终端进程 id
   * @param id 终端 id
   */
  getProcessId(id: string): number {
    return this.terminalService.getProcessId(id);
  }

  /**
   * 获取终端 shell 名称
   * @param id 终端 id
   */
  getShellName(id: string): string {
    return this.terminalService.getShellName(id);
  }

  /**
   * 获取当前操作系统类型
   */
  getOS(): OperatingSystem {
    return isWindows
      ? OperatingSystem.Windows
      : isMacintosh
      ? OperatingSystem.Macintosh
      : OperatingSystem.Linux;
  }

  /**
   * 销毁当前 client（暂未实现，避免重连时终端不可用）
   */
  dispose() {
    // TODO 后续需要一个合理的 Dispose 逻辑，暂时不要 Dispose，避免重连时终端不可用
    // this.terminalService.closeClient(this.clientId);
  }

  /**
   * 获取终端当前工作目录
   * @param id 终端 id
   */
  getCwd(id: string): Promise<string | undefined> {
    return this.terminalService.getCwd(id);
  }
}
